package org.javamap;

import java.awt.Image;


/**
  * Encapsulation of individual hexes.
  */
public class Hex implements java.io.Serializable
{
	public Hex()
	{
		parent = null;
	}
	
	/**
	  * Use createHex.
	  */
	private Hex(Hex parent)
	{
		this.parent = parent;
		
		// Set depth of parents:
		Hex curr = parent;
		int d = 1;
		while (curr != null) {
			++d;
			curr = curr.parent;
		}
		// d is now our total depth, -1.  Set depths of parents:
		int t = d;
		curr = parent;
		while (curr != null) {
			int newd = d - (--t);
			if (newd > curr.depth) curr.depth = newd;
			curr = curr.parent;
		}
	}
	
	/**
	  * Creates a child of this hex if it doesn't exist; otherwise acts as
	  *  {@link #getHex(int,int)}.  A child's imageKey is by default equal
	  *  to it's parent's.
	  */
	public Hex createHex(int row, int col)
	{
		Hex h;
		int index = col+row*NCHILDPER;
		if (children[index] == null) {
			setChild(index, h = new Hex(this));
			h.setImageKey(imageKey);
		}
		else h = children[index];
	
		return h;
	}
	
	public Hex getHex(int row, int col) { return getHex(row, col, 0, null); }
	
	public Hex getHex(int row, int col, int d)
	{ return getHex(row, col, d, null); }
	/**
	  * @param depthBelow levels below this hex's children.
	  */
	public Hex getHex(int row, int col, int depthBelow, Hex[] deepest)
	{
		Hex h;
		int ch_row = row/depthArray[depthBelow] % NCHILDPER,
			ch_col = col/depthArray[depthBelow] % NCHILDPER;
		h = children[ch_col+ch_row*NCHILDPER];
		if (depthBelow != 0 && h != null)
			// h will set deepest:
			return h.getHex(
					row,
					col,
					depthBelow-1,
					deepest
			);

		if (deepest != null) deepest[0] = this;
		return h;		
	}
	
	public int getDepth() { return depth; }
	
	public Image getImage()
	{ 
		if (image == null) image = ImageManager.retrieveImage(imageKey);
		return image; 
	}
	public String getImageKey() { return imageKey; }
	public void setImageKey(String key) 
	{
		if (immutable) throw new IllegalStateException(
				"Cannot set image key for immutable hex.");
System.err.println("Setting image key for "+this+" ("+parent+") = "+key);
		imageKey = key;
		image = ImageManager.retrieveImage(key);
	}
	
	public boolean isImmutable() { return immutable; }
	public void setImmutable(boolean onoff) { immutable = onoff; }
	
	public Hex getParent() { return parent; }
	
	public String toString()
	{
		return "Hex@"+hashCode()+"[d="+depth+", i="+imageKey+"]";
	}

//**************************  Utility Members  ******************************//
	private void setChild(int index, Hex child)
	{
		if (immutable) throw new IllegalStateException(
				"Cannot set child for immutable hex.");
		// Set in Hex constructor:
		//child.parent = this;
		children[index] = child;
		// Depth is set when child created:
		//if (depth < 1) depth = 1;
	}
	
//***************************  Data Members  ********************************//
	private final Hex parent;
	private final Hex[] children = new Hex[NCHILD];
	/**
	  * Number of levels of hexes available beneath this one.
	  */
	private int depth = 0;
	private transient Image image;
	private String imageKey;
	private boolean immutable = false;
	
	private static final int NCHILD = 16;
	static final int NCHILDPER = 4, MAXDEPTH = 10;
	static final int[] depthArray = new int[MAXDEPTH];
	
	static {
		depthArray[0] = 1;
		for (int ii = 1; ii < Hex.MAXDEPTH; ++ii) 
			depthArray[ii] = depthArray[ii-1]*Hex.NCHILDPER;
	}
}


